package org.jeecg.modules.flow.sys.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.basic.print.entity.PrintConfig;
import org.jeecg.modules.basic.print.entity.WmsDocumentTypeStatus;
import org.jeecg.modules.basic.print.mapper.PrintConfigMapper;
import org.jeecg.modules.basic.print.service.IWmsDocumentTypeStatusService;
import org.jeecg.modules.flow.record.entity.WmsFlowMain;
import org.jeecg.modules.flow.record.entity.WmsFlowRecord;
import org.jeecg.modules.flow.record.mapper.WmsFlowMainMapper;
import org.jeecg.modules.flow.record.service.IWmsFlowMainService;
import org.jeecg.modules.flow.record.service.IWmsFlowRecordService;
import org.jeecg.modules.flow.sys.base.SpringRunBean;
import org.jeecg.modules.flow.sys.constant.FlowConstant;
import org.jeecg.modules.flow.sys.entity.dto.BaseFlowDto;
import org.jeecg.modules.flow.sys.entity.dto.WorkFlowInfoDto;
import org.jeecg.modules.flow.sys.enumx.FlowFailTypeEnum;
import org.jeecg.modules.flow.sys.enumx.FlowRecordStatusEnum;
import org.jeecg.modules.flow.sys.exception.FlowCurrentFailException;
import org.jeecg.modules.flow.sys.exception.FlowNextFailException;
import org.jeecg.modules.flow.sys.exception.FlowNoActionException;
import org.jeecg.modules.flow.sys.service.DingDingSendMsgService;
import org.jeecg.modules.flow.sys.service.WorkFlowService;
import org.jeecg.modules.flow.sys.util.FlowStrUtil;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.utils.entity.WmsBaseDocument;
import org.jeecg.modules.utils.service.IWmsBaseDocumentService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/*
 * 项目名称:    wms-server-jeecg
 * 接口描述:    //
 * 创建人员:    zhaojun
 * 创建时间:    2023-09-13
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WorkFlowServiceImpl<T> implements WorkFlowService<T> {

    private final PlatformTransactionManager platformTransactionManager;
    private final IWmsDocumentTypeStatusService wmsDocumentTypeStatusService;
    private final IWmsFlowRecordService wmsFlowRecordService;
    private final IWmsFlowMainService iWmsFlowMainService;
    private final WmsFlowMainMapper wmsFlowMainMapper;
    private final PrintConfigMapper printConfigMapper;
    private final IWmsBaseDocumentService wmsBaseDocumentService;
    private final ISysUserService sysUserService;
    private final DingDingSendMsgService dingDingSendMsgService;

    private void createEndFlowRecord(List<WmsFlowRecord> flowRecords, List<WmsDocumentTypeStatus> wmsDocumentTypeStatuses) {
        int maxSort = flowRecords.stream().mapToInt(WmsFlowRecord::getSort).max().orElse(0);
        // 添加结束节点
        WmsFlowRecord endRecord = new WmsFlowRecord();
        endRecord.setFlowId(null);
        endRecord.setSort(maxSort + 1);
        endRecord.setFlowCode("end");
        endRecord.setFlowName("结束");
        endRecord.setDraft(FlowConstant.ONE);
        endRecord.setFailType(FlowFailTypeEnum.NO.getCode());
        endRecord.setVersion(0);
        endRecord.setAutoNext(1);
        endRecord.setStatus(FlowRecordStatusEnum.NOSTATUS.getCode());
        endRecord.setRequiredNode(FlowConstant.ONE);
        flowRecords.add(endRecord);
    }

    /**
     * 创建开始节点数据
     *
     * @param flowRecords
     */
    private void createStartFlowRecord(List<WmsFlowRecord> flowRecords) {
        // 添加开始节点
        WmsFlowRecord startRecord = new WmsFlowRecord();
        startRecord.setFlowId(null);
        startRecord.setFlowCode(FlowConstant.START);
        startRecord.setFlowName("开始");
        startRecord.setSort(-1);
        startRecord.setAutoNext(1);
        startRecord.setRequiredNode(FlowConstant.ONE);
        startRecord.setDraft(FlowConstant.ONE);
        startRecord.setFailType(FlowFailTypeEnum.NO.getCode());
        startRecord.setVersion(0);
        startRecord.setStatus(FlowRecordStatusEnum.SUCCESS.getCode());
        startRecord.setCompleteTime(new Date());
        startRecord.setUpdateTime(new Date());
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        startRecord.setLastOperator(ObjectUtils.isNotEmpty(sysUser) ? sysUser.getUsername() : "");
        flowRecords.add(startRecord);
    }

    @Override
    public List<WmsFlowRecord> workFlowInfo(WorkFlowInfoDto workFlowInfoDto) {
        if (StringUtils.isBlank(workFlowInfoDto.getInfoId()) && StringUtils.isBlank(workFlowInfoDto.getBusinessType())
                && StringUtils.isBlank(workFlowInfoDto.getDocumentType())) {
            throw new JeecgBootException("参数不能全部为空");
        }

        List<WmsFlowRecord> list = new ArrayList<>();
        // 按照业务数据查询流程当前节点的按钮信息
        if (StringUtils.isNotBlank(workFlowInfoDto.getInfoId())) {
            List<WmsFlowRecord> flowRecords = wmsFlowRecordService.list(new LambdaQueryWrapper<WmsFlowRecord>()
                    .eq(WmsFlowRecord::getInfoId, workFlowInfoDto.getInfoId())
                    .orderByAsc(WmsFlowRecord::getSort));
            // 查看流程是否中止
            List<WmsFlowRecord> interuptRecords = flowRecords.stream()
                    .filter(t -> FlowRecordStatusEnum.INTERRUPT.getCode().equals(t.getStatus()))
                    .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(interuptRecords)) {
                return Collections.emptyList();
            }

            Optional<WmsFlowRecord> first = flowRecords.stream()
                    .filter(t -> FlowRecordStatusEnum.EXECUTING.getCode().equals(t.getStatus())
                            || FlowRecordStatusEnum.PAUSE.getCode().equals(t.getStatus()))
                    .findFirst();
            if (first.isPresent()) {
                boolean hasContinue = true;
                for (WmsFlowRecord t : flowRecords) {
                    if (FlowConstant.START.equals(t.getFlowCode()) || FlowConstant.END.equals(t.getFlowCode())) {
                        continue;
                    }
                    if (!t.getFlowCode().equals(first.get().getFlowCode()) && hasContinue) {
                        continue;
                    } else {
                        hasContinue = false;
                    }
                    list.add(t);
                    // 草稿状态，必经节点可以跳过。直到找到非草稿必经为止
                    if (FlowConstant.ZERO.equals(t.getDraft())) {
                        continue;
                    }
                    // 从相等的后一个开始处理
                    if (FlowConstant.ZERO.equals(t.getRequiredNode())) {
                        break;
                    }
                }
            }
        } else {
            if (StringUtils.isBlank(workFlowInfoDto.getBusinessType()) || StringUtils.isBlank(workFlowInfoDto.getDocumentType())) {
                throw new JeecgBootException("参数不能为空");
            }
            PrintConfig printConfig = printConfigMapper.selectOne(new LambdaQueryWrapper<PrintConfig>()
                    .eq(PrintConfig::getBusinessType, workFlowInfoDto.getBusinessType())
                    .eq(PrintConfig::getDocumentType, workFlowInfoDto.getDocumentType()));
            if (ObjectUtils.isEmpty(printConfig)) {
                throw new JeecgBootException("未维护当前业务类型和单据类型");
            }
            List<WmsDocumentTypeStatus> wmsDocumentTypeStatuses = wmsDocumentTypeStatusService.list(
                    new LambdaQueryWrapper<WmsDocumentTypeStatus>()
                            .eq(WmsDocumentTypeStatus::getPrintConfigId, printConfig.getId())
            );
            if (CollectionUtil.isNotEmpty(wmsDocumentTypeStatuses)) {
                WmsFlowRecord wmsFlowRecord = null;
                for (WmsDocumentTypeStatus t : wmsDocumentTypeStatuses) {
                    wmsFlowRecord = new WmsFlowRecord();
                    BeanUtils.copyProperties(t, wmsFlowRecord);
                    wmsFlowRecord.setFlowCode(t.getCode());
                    wmsFlowRecord.setFlowName(t.getName());
                    list.add(wmsFlowRecord);
                    // 如果当前记录未草稿状态
                    if (FlowConstant.ZERO.equals(t.getDraft())) {
                        continue;
                    }
                    // 草稿状态，必经节点可以跳过。直到找到非草稿必经为止
                    if (FlowConstant.ZERO.equals(t.getRequiredNode())) {
                        break;
                    }
                }
            }
        }
        return list;
    }

    @Override
    @SuppressWarnings({"unchecked", "rawtypes"})
    @Transactional(rollbackFor = Exception.class)
    public void commit(BaseFlowDto base) {
        log.info("流程节点开始，信息：{}", base);
        long start = System.currentTimeMillis();
        if (StringUtils.isBlank(base.getCode())) {
            throw new JeecgBootException("提交流程必须要填写code");
        }
        // 查询流程记录信息
        List<WmsFlowRecord> flowRecords = createNodeRecords(base);
        // 组装节点信息并校验
        packageAndValidRecordInfo(base, flowRecords);
        // 处理当前节点执行前的回调
        boolean result = dealCurrentNode(base);
        if (!result) {
            return;
        }
        // 执行节点成功的回调
        dealCurrentNodeSuccess(base);
        // 处理下个节点的初始化回调
        doNextNode(base);
        // 更新节点信息
        updateNode(base);
        // 自动流转节点信息
        if (!base.getRunThenStop()) {
            autoCommit(base);
        }
        // 异步发送钉钉消息
        CompletableFuture.runAsync(() -> {
            dingDingSendMsgService.dealInfo(base);
        });
        long end = System.currentTimeMillis();
        log.info("流程节点结束，花费时间，{}ms", (end - start));
    }

    /**
     * 执行节点成功的回调
     *
     * @param base
     */
    @Transactional(rollbackFor = Exception.class)
    public void dealCurrentNodeSuccess(BaseFlowDto base) {
        log.info("开始处理流程当前流程节点-成功回调");
        Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
        // 节点更新后成功的回调,执行成功与否都不能回滚事务，只能捕获异常。做记录
        if (StringUtils.isNotBlank(base.getCurrentWmsFlowRecord().getCallbackSuccess())) {
            try {
                List<String> callbackSuccesses = Arrays.stream(base.getCurrentWmsFlowRecord().getCallbackSuccess().split(",")).collect(Collectors.toList());
                callbackSuccesses.forEach(callBack -> {
                    log.info("开始执行成功回调：【{}】", callBack);
                    base.setExtraParam(FlowStrUtil.translateParam(callBack));
                    SpringRunBean springRunBean = new SpringRunBean(FlowStrUtil.removeLastStr(callBack), base);
                    springRunBean.call();
                    log.info("结束执行成功回调：【{}】", callBack);
                });
            } catch (Exception e) {
                log.error("成功的回调出现异常,异常信息：{}", e.getMessage(), e);
                TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
            }
        }
        log.info("完成处理流程当前流程节点-成功回调");
    }

    /**
     * 自动流传节点信息
     *
     * @param base
     */
    @Transactional(rollbackFor = Exception.class)
    public void autoCommit(BaseFlowDto base) {
        WmsFlowRecord nextWmsFlowRecord = base.getNextWmsFlowRecord();
        WmsFlowRecord currentWmsFlowRecord = base.getCurrentWmsFlowRecord();
        // 自动执行下个节点，仅仅将下个节点作为一次任务节点记录一下
        if (FlowRecordStatusEnum.SUCCESS.getCode().equals(currentWmsFlowRecord.getStatus())) {
            if (ObjectUtils.isNotEmpty(nextWmsFlowRecord) && nextWmsFlowRecord.getAutoNext() == 0) {
                BaseFlowDto baseFlowDto = backAutoCommit(nextWmsFlowRecord.getInfoId(), (T) base.getData());
                if (ObjectUtils.isNotEmpty(baseFlowDto)) {
                    // 重置
                    baseFlowDto.setRunThenStop(false);
                    BeanUtils.copyProperties(baseFlowDto, base);
                }
            }
        }
    }

    /**
     * 更新节点信息
     *
     * @param base
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateNode(BaseFlowDto base) {
        WmsFlowRecord nextWmsFlowRecord = base.getNextWmsFlowRecord();
        WmsFlowRecord currentWmsFlowRecord = base.getCurrentWmsFlowRecord();
        List<WmsFlowRecord> jumpRecords = base.getJumpRecords();
        WmsFlowMain wmsFlowMain = iWmsFlowMainService.getOne(new LambdaQueryWrapper<WmsFlowMain>()
                .eq(WmsFlowMain::getInfoId, base.getInfoId()));
        if (FlowConstant.ONE.equals(currentWmsFlowRecord.getDraft())) {
            wmsFlowMain.setCurrentStep(nextWmsFlowRecord.getFlowCode());
            wmsFlowMain.setCurrentStepName(nextWmsFlowRecord.getFlowName());
            if (wmsFlowMain.getCurrentStep().equals(FlowConstant.END) && !base.getCurrentFailed()) {
                nextWmsFlowRecord.setCompleteTime(new Date());
                LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
                nextWmsFlowRecord.setLastOperator(ObjectUtils.isNotEmpty(sysUser) ? sysUser.getUsername() : "");
                nextWmsFlowRecord.setStatus(FlowRecordStatusEnum.SUCCESS.getCode());
                wmsFlowRecordService.updateById(nextWmsFlowRecord);
                wmsFlowMain.setCurrentStatus(2);
            } else {
                wmsFlowMain.setCurrentStatus(1);
            }
            iWmsFlowMainService.updateById(wmsFlowMain);
        }

        if (CollectionUtil.isNotEmpty(jumpRecords)) {
            wmsFlowRecordService.updateBatchById(jumpRecords);
        }
    }

    /**
     * 处理下个节点初始化回调
     *
     * @param base
     */
    @Transactional(rollbackFor = Exception.class)
    public void doNextNode(BaseFlowDto base) {
        WmsFlowRecord currentWmsFlowRecord = base.getCurrentWmsFlowRecord();
        List<WmsFlowRecord> dealRecords = base.getDealRecords();
        // 处理的当前流程为非草稿状态,处理下面的流程
        if (FlowConstant.ONE.equals(currentWmsFlowRecord.getDraft()) && dealRecords.size() > 1) {
            if (FlowConstant.ZERO.equals(currentWmsFlowRecord.getRequiredNode())
                    && FlowRecordStatusEnum.FAIL.getCode().equals(currentWmsFlowRecord.getStatus())) {
                log.error("当前节点为必经节点且执行失败，其他回调及下个节点的状态不做处理");
            } else {
                dealNextNode(base);
            }
        }
    }

    /**
     * 组装节点信息并校验
     *
     * @param base
     * @param flowRecords
     */
    public void packageAndValidRecordInfo(BaseFlowDto base, List<WmsFlowRecord> flowRecords) {
        log.info("开始组装校验节点信息");
        WmsFlowRecord currentWmsFlowRecord = null;
        WmsFlowRecord nextWmsFlowRecord = null;
        List<WmsFlowRecord> dealRecords = new ArrayList<>();
        // 当前节点和下个节点的中间节点流程记录
        List<WmsFlowRecord> jumpRecords = new ArrayList<>();
        // 当前节点之前的操作节点
        List<WmsFlowRecord> completeRecords = new ArrayList<>();
        boolean validFlowRecord = false;
        for (int i = 0; i < flowRecords.size(); i++) {
            if (FlowRecordStatusEnum.INTERRUPT.getCode().equals(flowRecords.get(i).getStatus())) {
                throw new JeecgBootException("当前流程已中止，不允许任何操作");
            }
            if (flowRecords.get(i).getFlowCode().equals(base.getCode())) {
                // 判断当前节点是否已经执行
                if (FlowRecordStatusEnum.JUMP.getCode().equals(flowRecords.get(i).getStatus()) ||
                        FlowRecordStatusEnum.SUCCESS.getCode().equals(flowRecords.get(i).getStatus())) {
                    throw new JeecgBootException("当前节点【" + flowRecords.get(i).getFlowName() + "】已执行或者跳过，不能重复执行");
                }
                // 当前节点
                dealRecords.add(flowRecords.get(i));
                validFlowRecord = true;
                continue;
            }
            if (!validFlowRecord) {
                WmsFlowRecord record = flowRecords.get(i);
                if (FlowRecordStatusEnum.INTERRUPT.getCode().equals(record.getStatus())) {
                    throw new JeecgBootException("当前流程已中止，不允许提交节点");
                }
                if (FlowRecordStatusEnum.NOSTATUS.getCode().equals(record.getStatus())) {
                    // 可以跳过的节点
                    if (FlowConstant.ONE.equals(record.getRequiredNode())) {
                        record.setStatus(FlowRecordStatusEnum.JUMP.getCode());
                    } else {
                        throw new JeecgBootException("当前流程存在跳过必经节点，必经节点为：" +
                                flowRecords.get(i).getFlowName());
                    }

                }
                if (FlowRecordStatusEnum.FAIL.getCode().equals(record.getStatus())
                        && FlowConstant.ZERO.equals(record.getRequiredNode())) {
                    throw new JeecgBootException("当前流程存在必经节点【" + record.getFlowName() + "】执行失败");
                }
                completeRecords.add(flowRecords.get(i));
            }
            if (validFlowRecord) {
                dealRecords.add(flowRecords.get(i));
                break;
            }
        }
        for (WmsFlowRecord record : completeRecords) {
            // 历史节点是草稿就可以跳过
            if (FlowConstant.ZERO.equals(record.getDraft())) {
                if (FlowRecordStatusEnum.SUCCESS.getCode().equals(record.getStatus())) {
                    continue;
                }
                if (record.getVersion() > 0) {
                    record.setStatus(FlowRecordStatusEnum.SUCCESS.getCode());
                } else {
                    record.setStatus(FlowRecordStatusEnum.JUMP.getCode());
                    if (FlowConstant.ZERO.equals(record.getRequiredNode())) {
                        throw new JeecgBootException("当前流程存在草稿节点为必经节点【" +
                                record.getFlowName() + "】且未提交");
                    }
                }
                jumpRecords.add(record);
            } else {
                // 历史节点非草稿需要判断是否在执行中
                if (FlowRecordStatusEnum.EXECUTING.getCode().equals(record.getStatus()) ||
                        FlowRecordStatusEnum.PAUSE.getCode().equals(record.getStatus())) {
                    if (FlowConstant.ONE.equals(record.getRequiredNode())) {
                        record.setStatus(FlowRecordStatusEnum.JUMP.getCode());
                        jumpRecords.add(record);
                    } else {
                        throw new JeecgBootException("当前流程存在节点【" + record.getFlowName() + "】未执行完");
                    }
                }
            }
        }
        currentWmsFlowRecord = dealRecords.get(0);

        if (CollectionUtil.isNotEmpty(dealRecords)) {
            base.setFlowRecords(flowRecords);
            base.setDealRecords(dealRecords);
            base.setJumpRecords(jumpRecords);
            base.setCurrentWmsFlowRecord(currentWmsFlowRecord);
            if (dealRecords.size() > 1) {
                nextWmsFlowRecord = dealRecords.get(1);
                base.setNextWmsFlowRecord(nextWmsFlowRecord);
            }
        }
        log.info("结束组装校验节点信息");
    }

    /**
     * 创建节点记录信息
     *
     * @param base
     */
    @Transactional(rollbackFor = Exception.class)
    public List<WmsFlowRecord> createNodeRecords(BaseFlowDto base) {
        log.info("开始处理节点信息");
        List<WmsFlowRecord> flowRecords = null;

        if (StringUtils.isNotBlank(base.getInfoId())) {
            flowRecords = wmsFlowRecordService.list(new LambdaQueryWrapper<WmsFlowRecord>()
                    .eq(WmsFlowRecord::getInfoId, base.getInfoId())
                    .orderByAsc(WmsFlowRecord::getSort));
        }
        if (CollectionUtil.isEmpty(flowRecords)) {
            log.info("生成节点信息");
            flowRecords = new ArrayList<>();
            PrintConfig printConfig = printConfigMapper.selectOne(new LambdaQueryWrapper<PrintConfig>()
                    .eq(PrintConfig::getBusinessType, base.getBusinessType())
                    .eq(PrintConfig::getDocumentType, base.getDocumentType()));
            if (ObjectUtils.isEmpty(printConfig)) {
                throw new JeecgBootException("未维护当前业务类型和单据类型");
            }
            List<WmsDocumentTypeStatus> wmsDocumentTypeStatuses = wmsDocumentTypeStatusService.list(
                    new LambdaQueryWrapper<WmsDocumentTypeStatus>()
                            .eq(WmsDocumentTypeStatus::getPrintConfigId, printConfig.getId())
                            .orderByAsc(WmsDocumentTypeStatus::getSort)
            );

            if (CollectionUtil.isEmpty(wmsDocumentTypeStatuses)) {
                throw new JeecgBootException("当前业务类型和单据类型未匹配请核对");
            }

            WmsFlowRecord wmsFlowRecord = null;
            // 创建开始节点记录
            createStartFlowRecord(flowRecords);

            for (WmsDocumentTypeStatus t : wmsDocumentTypeStatuses) {
                wmsFlowRecord = new WmsFlowRecord();
                BeanUtils.copyProperties(t, wmsFlowRecord, "id");
                wmsFlowRecord.setVersion(0);
                wmsFlowRecord.setFlowCode(t.getCode());
                wmsFlowRecord.setFlowName(t.getName());
                wmsFlowRecord.setFailType(FlowFailTypeEnum.NO.getCode());
                flowRecords.add(wmsFlowRecord);
            }

            // 创建结束节点记录
            createEndFlowRecord(flowRecords, wmsDocumentTypeStatuses);
        }
        log.info("结束处理节点信息");
        return flowRecords;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void retry(BaseFlowDto base) {
        // 查询所有流程节点
        WmsFlowRecord currentRecord = wmsFlowRecordService.getOne(new LambdaQueryWrapper<WmsFlowRecord>()
                .eq(WmsFlowRecord::getInfoId, base.getInfoId())
                .eq(WmsFlowRecord::getFlowCode, base.getCode())
        );
        // 回调前失败
        if (Objects.equals(currentRecord.getFailType(), FlowFailTypeEnum.BEFORE.getCode())) {
            commit(base);
        }

        // 初始化回调失败
        if (Objects.equals(currentRecord.getFailType(), FlowFailTypeEnum.INIT.getCode())) {
            // 执行当前节点的初始化回调
            base.setNextWmsFlowRecord(currentRecord);
            dealNextNode(base);

            if (!base.getNextFailed()) {
                // 自动执行下个节点，仅仅将下个节点作为一次任务节点记录一下
                if (currentRecord.getAutoNext() == 0) {
                    BaseFlowDto baseFlowDto = backAutoCommit(currentRecord.getInfoId(), (T) base.getData());
                    if (ObjectUtils.isNotEmpty(baseFlowDto)) {
                        BeanUtils.copyProperties(baseFlowDto, base);
                    }
                }
            }
        }
    }

    @Override
    public void interrupt(BaseFlowDto base) {
        log.info("流程中止开始，信息：{}", base);
        long start = System.currentTimeMillis();
        // 查询流程记录信息
        List<WmsFlowRecord> flowRecords = wmsFlowRecordService.list(new LambdaQueryWrapper<WmsFlowRecord>()
                .eq(WmsFlowRecord::getInfoId, base.getInfoId()).orderByAsc(WmsFlowRecord::getSort));

        if (StringUtils.isBlank(base.getCode())) {
            Optional<WmsFlowRecord> first = flowRecords.stream().sorted(Comparator.comparingInt(t -> t.getSort()))
                    .filter(t -> FlowRecordStatusEnum.EXECUTING.getCode().equals(t.getStatus()) ||
                            FlowRecordStatusEnum.PAUSE.getCode().equals(t.getStatus())).findFirst();
            if (!first.isPresent()) {
                throw new JeecgBootException("无进行中的节点");
            }
            base.setCode(first.get().getFlowCode());
        }

        List<WmsFlowRecord> dealRecords = new ArrayList<>();
        // 当前节点和下个节点的中间节点流程记录
        List<WmsFlowRecord> jumpRecords = new ArrayList<>();
        // 当前节点之前的操作节点
        List<WmsFlowRecord> completeRecords = new ArrayList<>();
        boolean validFlowRecord = false;
        for (int i = 0; i < flowRecords.size(); i++) {
            if (flowRecords.get(i).getFlowCode().equals(base.getCode())) {
                if (FlowRecordStatusEnum.SUCCESS.getCode().equals(flowRecords.get(i).getStatus())) {
                    throw new JeecgBootException("当前节点已成功无法中止");
                }
                // 当前节点
                dealRecords.add(flowRecords.get(i));
                validFlowRecord = true;
                if (flowRecords.get(i).getInterrupted() == 0) {
                    break;
                }
                continue;
            }
            if (!validFlowRecord) {
                WmsFlowRecord record = flowRecords.get(i);
                if (FlowRecordStatusEnum.NOSTATUS.getCode().equals(record.getStatus())) {
                    // 可以跳过的节点
                    if (FlowConstant.ONE.equals(record.getRequiredNode())) {
                        record.setStatus(FlowRecordStatusEnum.JUMP.getCode());
                    } else {
                        throw new JeecgBootException("当前流程存在跳过必经节点，必经节点为：" +
                                flowRecords.get(i).getFlowName());
                    }
                }
                if (FlowRecordStatusEnum.FAIL.getCode().equals(record.getStatus())
                        && FlowConstant.ZERO.equals(record.getRequiredNode())) {
                    throw new JeecgBootException("当前流程存在必经节点【" + record.getFlowName() + "】执行失败");
                }
                completeRecords.add(flowRecords.get(i));
            }
            if (validFlowRecord) {
                dealRecords.add(flowRecords.get(i));
                break;
            }
        }
        for (WmsFlowRecord record : completeRecords) {
            // 历史节点是草稿就可以跳过
            if (FlowConstant.ZERO.equals(record.getDraft())) {
                if (record.getVersion() > 0) {
                    record.setStatus(FlowRecordStatusEnum.SUCCESS.getCode());
                } else {
                    record.setStatus(FlowRecordStatusEnum.JUMP.getCode());
                    if (FlowConstant.ZERO.equals(record.getRequiredNode())) {
                        throw new JeecgBootException("当前流程存在草稿节点为必经节点【" +
                                record.getFlowName() + "】且未提交");
                    }
                }
                jumpRecords.add(record);
            } else {
                // 历史节点非草稿需要判断是否在执行中
                if (FlowRecordStatusEnum.EXECUTING.getCode().equals(record.getStatus())
                        || FlowRecordStatusEnum.PAUSE.getCode().equals(record.getStatus())) {
                    if (FlowConstant.ONE.equals(record.getRequiredNode())) {
                        record.setStatus(FlowRecordStatusEnum.JUMP.getCode());
                        jumpRecords.add(record);
                    } else {
                        throw new JeecgBootException("当前流程存在节点【" + record.getFlowName() + "】未执行完");
                    }
                }
            }
        }
        if (CollectionUtil.isNotEmpty(dealRecords)) {
            if (StringUtils.isBlank(base.getInfoId())) {
                base.setFlowRecords(flowRecords);
                base.setDealRecords(dealRecords);
                base.setJumpRecords(jumpRecords);
            }
            WmsFlowRecord currentWmsFlowRecord = dealRecords.get(0);
            base.setCurrentWmsFlowRecord(currentWmsFlowRecord);

            dealInterruptNode(base);
            WmsFlowMain wmsFlowMain = iWmsFlowMainService.getOne(
                    new LambdaQueryWrapper<WmsFlowMain>().eq(WmsFlowMain::getInfoId, base.getInfoId())
            );
            wmsFlowMain.setCurrentStep(base.getCurrentWmsFlowRecord().getFlowCode());
            wmsFlowMain.setCurrentStepName(base.getCurrentWmsFlowRecord().getFlowName());
            wmsFlowMain.setCurrentStatus(3);
            wmsFlowMainMapper.updateById(wmsFlowMain);
        }
        if (CollectionUtil.isNotEmpty(jumpRecords)) {
            wmsFlowRecordService.updateBatchById(jumpRecords);
        }
        long end = System.currentTimeMillis();
        log.info("流程中止结束，花费时间，{}ms", (end - start));
    }

    /**
     * 处理当前节点
     *
     * @param base 提交信息
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean dealCurrentNode(BaseFlowDto base) {
        log.info("开始处理流程当前流程节点-事前回调，流程信息id，{}节点编码，{}", base.getCurrentWmsFlowRecord().getFlowId(),
                base.getCurrentWmsFlowRecord().getFlowCode());
        if (StringUtils.isNotBlank(base.getCurrentWmsFlowRecord().getCallbackBefore())) {
            try {
                List<String> callbackBefores = Arrays.stream(base.getCurrentWmsFlowRecord().getCallbackBefore().split(",")).collect(Collectors.toList());
                callbackBefores.forEach(callBack -> {
                    log.info("开始执行事前回调：【{}】", callBack);
                    base.setExtraParam(FlowStrUtil.translateParam(callBack));
                    SpringRunBean springRunBean = new SpringRunBean(FlowStrUtil.removeLastStr(callBack), base);
                    springRunBean.call();
                    log.info("结束执行事前回调：【{}】", callBack);
                });
            } catch (Exception e) {
                log.error("节点提交之前的回调异常,异常信息：{}", e.getMessage(), e);
                if (e instanceof FlowCurrentFailException) {
                    base.setCurrentFailed(true);
                } else if (e instanceof FlowNoActionException) {
                    log.info("当前节点不需要更新，并且当前回调需要抛出异常进行流程记录回滚，业务记录回滚");
                    //手动强制回滚事务，这里一定要第一时间处理
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return false;
                } else {
                    throw new JeecgBootException(e.getMessage());
                }
            }
        }

        if (base.getRunThenStop()) {
            return false;
        }

        if (FlowConstant.ONE.equals(base.getCurrentWmsFlowRecord().getDraft())) {
            // 更新当前节点
            base.getCurrentWmsFlowRecord().setStatus(FlowRecordStatusEnum.SUCCESS.getCode());
        } else {
            base.getCurrentWmsFlowRecord().setVersion(base.getCurrentWmsFlowRecord().getVersion() + 1);
        }
        base.getCurrentWmsFlowRecord().setCompleteTime(new Date());
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        base.getCurrentWmsFlowRecord().setLastOperator(ObjectUtils.isNotEmpty(sysUser) ? sysUser.getUsername() : "");

        if (base.getCurrentFailed()) {
            base.getCurrentWmsFlowRecord().setStatus(FlowRecordStatusEnum.FAIL.getCode());
            base.getCurrentWmsFlowRecord().setFailType(FlowFailTypeEnum.BEFORE.getCode());
        }
        wmsFlowRecordService.updateById(base.getCurrentWmsFlowRecord());
        log.info("完成处理流程当前流程节点-事前回调");
        return true;
    }

    /**
     * 处理下个节点
     *
     * @param base 提交信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void dealNextNode(BaseFlowDto base) {
        log.info("开始处理下一个流程节点，流程信息id，{}节点编码，{}", base.getNextWmsFlowRecord().getFlowId()
                , base.getNextWmsFlowRecord().getFlowCode());
        // 执行节点调用前
        Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
        if (StringUtils.isNotBlank(base.getNextWmsFlowRecord().getCallbackCreated())) {
            try {
                List<String> callbackInits = Arrays.stream(base.getNextWmsFlowRecord().getCallbackCreated().split(",")).collect(Collectors.toList());
                callbackInits.forEach(callBack -> {
                    log.info("开始执行初始化回调：【{}】", callBack);
                    base.setExtraParam(FlowStrUtil.translateParam(callBack));
                    SpringRunBean springRunBean = new SpringRunBean(FlowStrUtil.removeLastStr(callBack), base);
                    springRunBean.call();
                    log.info("结束执行初始化回调：【{}】", callBack);
                });
            } catch (Exception e) {
                log.error("节点创建完成以后的回调出现异常,异常信息：{}", e.getMessage(), e);
                if (e instanceof FlowNextFailException) {
                    base.setNextFailed(true);
                } else {
                    TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
                    return;
                }
            }
        }
        base.getNextWmsFlowRecord().setStatus(FlowRecordStatusEnum.EXECUTING.getCode());
        if (base.getNextFailed()) {
            base.getNextWmsFlowRecord().setStatus(FlowRecordStatusEnum.FAIL.getCode());
            base.getNextWmsFlowRecord().setFailType(FlowFailTypeEnum.INIT.getCode());
        }
        wmsFlowRecordService.updateById(base.getNextWmsFlowRecord());
        log.info("完成处理下一个流程节点");
    }

    /**
     * 处理中止节点
     *
     * @param base
     */
    @Transactional(rollbackFor = Exception.class)
    public void dealInterruptNode(BaseFlowDto base) {
        log.info("开始处理中止流程节点，流程信息id，{}节点编码，{}", base.getCurrentWmsFlowRecord().getFlowId()
                , base.getCurrentWmsFlowRecord().getFlowCode());

        if (ObjectUtils.isEmpty(base.getRefuseType())) {
            throw new JeecgBootException("中止的类型未填，中止参数【refuseType】说明：中止的原因 1、手工关闭  2、强制完成 3、取消");
        }

        // 执行节点调用前
        if (base.getCurrentWmsFlowRecord().getInterrupted() == 1) {
            throw new JeecgBootException("当前节点不是中止节点，不能中止");
        }
        if (StringUtils.isNotBlank(base.getCurrentWmsFlowRecord().getCallbackInterrupted())) {
            try {
                List<String> callbackInterrupt = Arrays.stream(base.getCurrentWmsFlowRecord().getCallbackInterrupted().split(",")).collect(Collectors.toList());
                callbackInterrupt.forEach(callBack -> {
                    log.info("开始执行中止回调：【{}】", callBack);
                    base.setExtraParam(FlowStrUtil.translateParam(callBack));
                    SpringRunBean springRunBean = new SpringRunBean(FlowStrUtil.removeLastStr(callBack), base);
                    springRunBean.call();
                    log.info("结束执行中止回调：【{}】", callBack);
                });
            } catch (Exception e) {
                log.error("节点创建完成以后的回调出现异常,异常信息：{}", e.getMessage(), e);
                if (e instanceof FlowCurrentFailException) {
                    base.setCurrentFailed(true);
                } else if (e instanceof FlowNoActionException) {
                    log.info("当前节点不需要更新，并且当前回调需要抛出异常进行流程记录回滚，业务记录回滚");
                    //手动强制回滚事务，这里一定要第一时间处理
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                } else {
                    throw new JeecgBootException(e.getMessage());
                }
            }
        }
        if (base.getCurrentFailed()) {
            base.getCurrentWmsFlowRecord().setStatus(FlowRecordStatusEnum.FAIL.getCode());
        } else {
            base.getCurrentWmsFlowRecord().setStatus(FlowRecordStatusEnum.INTERRUPT.getCode());
        }

        base.getCurrentWmsFlowRecord().setRemark(base.getRemark());
        base.getCurrentWmsFlowRecord().setRefuseType(base.getRefuseType());
        wmsFlowRecordService.updateById(base.getCurrentWmsFlowRecord());
        log.info("完成处理中止流程节点");
    }

    @Override
    public void callFail(String code, String infoId) {
        // 获取字典流程信息
        WmsDocumentTypeStatus status = wmsDocumentTypeStatusService.getOne(new LambdaQueryWrapper<WmsDocumentTypeStatus>()
                .eq(WmsDocumentTypeStatus::getCode, code));
        // 处理当前节点
        WmsFlowMain wmsFlowMain = iWmsFlowMainService.getOne(new LambdaQueryWrapper<WmsFlowMain>()
                .eq(WmsFlowMain::getPrintId, status.getPrintConfigId())
                .eq(WmsFlowMain::getInfoId, infoId));

        WmsFlowRecord record = wmsFlowRecordService.getOne(new LambdaQueryWrapper<WmsFlowRecord>()
                .eq(WmsFlowRecord::getFlowId, wmsFlowMain.getId())
                .eq(WmsFlowRecord::getFlowCode, code)
        );
        record.setStatus(FlowRecordStatusEnum.FAIL.getCode());

        wmsFlowRecordService.updateById(record);
    }

    @Override
    public List<WmsFlowRecord> currentBussienssRecords(String infoId) {
        WmsFlowMain wmsFlowMain = wmsFlowMainMapper.selectOne(new LambdaQueryWrapper<WmsFlowMain>()
                .eq(WmsFlowMain::getInfoId, infoId));
        if (ObjectUtils.isEmpty(wmsFlowMain)) {
            return Collections.emptyList();
        }
        List<WmsFlowRecord> flowRecords = wmsFlowRecordService.selectByMainId(wmsFlowMain.getId());
        flowRecords = flowRecords.stream().sorted(Comparator.comparingInt(t -> t.getSort())).collect(Collectors.toList());
        List<String> opreators = flowRecords.stream().map(t -> t.getLastOperator()).distinct().collect(Collectors.toList());
        List<SysUser> userList = sysUserService.list(new LambdaQueryWrapper<SysUser>().in(SysUser::getUsername, opreators));
        if (CollectionUtil.isNotEmpty(userList)) {
            Map<String, String> userMap = userList.stream().collect(Collectors.toMap(t -> t.getUsername(), a -> a.getRealname()));
            flowRecords.forEach(t -> {
                if (StringUtils.isNotBlank(userMap.get(t.getLastOperator()))) {
                    t.setLastOperator(userMap.get(t.getLastOperator()));
                }
            });
        }
        return flowRecords;
    }

    @Override
    public void createFlowRecord(BaseFlowDto base) {
        long count = wmsFlowRecordService.count(new LambdaQueryWrapper<WmsFlowRecord>().eq(WmsFlowRecord::getInfoId, base.getInfoId()));
        if (count > 0) {
            return;
        }
        // 第一次创建流程信息
        if (StringUtils.isBlank(base.getBusinessType()) || StringUtils.isBlank(base.getDocumentType())) {
            throw new JeecgBootException("草稿状态，缺少业务类型或者单据类型");
        }
        PrintConfig printConfig = printConfigMapper.selectOne(new LambdaQueryWrapper<PrintConfig>()
                .eq(PrintConfig::getBusinessType, base.getBusinessType()).eq(PrintConfig::getDocumentType, base.getDocumentType()));

        if (ObjectUtils.isEmpty(printConfig)) {
            throw new JeecgBootException("根据业务类型，单据类型查询，缺少打印类型记录，请维护");
        }
        log.info("创建流程节点记录信息开始");
        // 生成流程状态表
        WmsFlowMain wmsFlowMain = new WmsFlowMain();
        wmsFlowMain.setInfoId(base.getInfoId());
        wmsFlowMain.setCurrentStep(base.getCode());
        wmsFlowMain.setPrintId(printConfig.getId());
        wmsFlowMain.setCurrentStatus(0);
        iWmsFlowMainService.save(wmsFlowMain);
        // 生成流程信息表
        WmsFlowMain finalWmsFlowMain = wmsFlowMain;
        List<WmsFlowRecord> allFlowRecords = new ArrayList<>();
        List<WmsFlowRecord> finalCreateWmsFlowRecords = new ArrayList<>();

        AtomicBoolean firstRecord = new AtomicBoolean(true);

        base.getFlowRecords().forEach(t -> {
            WmsFlowRecord wmsFlowRecord = (WmsFlowRecord) t;
            wmsFlowRecord.setId(null);
            wmsFlowRecord.setCreateTime(null);
            wmsFlowRecord.setCreateBy(null);
            wmsFlowRecord.setVersion(0);
            wmsFlowRecord.setFlowId(finalWmsFlowMain.getId());
            if (FlowConstant.START.equals(wmsFlowRecord.getFlowCode())) {
                wmsFlowRecord.setStatus(FlowRecordStatusEnum.SUCCESS.getCode());
            } else {
                if (ObjectUtils.isEmpty(wmsFlowRecord.getStatus())) {
                    wmsFlowRecord.setStatus(firstRecord.get() ? FlowRecordStatusEnum.EXECUTING.getCode() : FlowRecordStatusEnum.NOSTATUS.getCode());
                    firstRecord.set(false);
                }
            }
            wmsFlowRecord.setInfoId(base.getInfoId());
            finalCreateWmsFlowRecords.add(wmsFlowRecord);

            allFlowRecords.add(wmsFlowRecord);
            t = wmsFlowRecord;
        });
        if (CollectionUtil.isNotEmpty(finalCreateWmsFlowRecords)) {
            log.info("批量插入流程记录,info_id={},记录id={}", finalCreateWmsFlowRecords.get(0).getInfoId(),
                    finalCreateWmsFlowRecords.stream().map(t -> t.getFlowId()).collect(Collectors.joining(",")));
        }
        wmsFlowRecordService.saveBatch(finalCreateWmsFlowRecords);

        log.info("创建流程节点记录信息结束");
        base.setFlowRecords(allFlowRecords);
        Map<String, WmsFlowRecord> allWmsFlowRecordMap = allFlowRecords.stream().collect(Collectors.
                toMap(t -> t.getFlowCode(), a -> a));
        // 状态的修改
        base.getDealRecords().forEach(t -> {
            WmsFlowRecord wmsFlowRecord = (WmsFlowRecord) t;
            BeanUtils.copyProperties(allWmsFlowRecordMap.get(wmsFlowRecord.getFlowCode()), wmsFlowRecord,
                    "status");
            t = wmsFlowRecord;
        });

        base.getJumpRecords().forEach(t -> {
            WmsFlowRecord wmsFlowRecord = (WmsFlowRecord) t;
            BeanUtils.copyProperties(allWmsFlowRecordMap.get(wmsFlowRecord.getFlowCode()), wmsFlowRecord,
                    "status");
            t = wmsFlowRecord;
        });
        if (ObjectUtils.isNotEmpty(base.getCurrentWmsFlowRecord())) {
            BeanUtils.copyProperties(allWmsFlowRecordMap.get(base.getCurrentWmsFlowRecord().getFlowCode()),
                    base.getCurrentWmsFlowRecord(), "status");
        }
        if (ObjectUtils.isNotEmpty(base.getNextWmsFlowRecord())) {
            BeanUtils.copyProperties(allWmsFlowRecordMap.get(base.getNextWmsFlowRecord().getFlowCode()),
                    base.getNextWmsFlowRecord(), "status");
        }
    }

    @Override
    public void delete(String infoId) {
        WmsBaseDocument baseDocument = wmsBaseDocumentService.getById(infoId);
        if (ObjectUtils.isEmpty(baseDocument)) {
            log.error("删除当前草稿失败，找不到当前infoId,{}", infoId);
            throw new JeecgBootException("删除当前草稿失败，找不到当前infoId=" + infoId);
        }
        wmsFlowMainMapper.deleteTableById(baseDocument.getTableName(), infoId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseFlowDto backAutoCommit(String infoId, T data) {
        WmsFlowRecord flowRecord = wmsFlowRecordService.getOne(new LambdaQueryWrapper<WmsFlowRecord>()
                .eq(WmsFlowRecord::getInfoId, infoId)
                .in(WmsFlowRecord::getStatus, Arrays.asList(
                                FlowRecordStatusEnum.EXECUTING.getCode()
                                , FlowRecordStatusEnum.PAUSE.getCode()
                        )
                )
                .orderByAsc(WmsFlowRecord::getSort)
                .last("limit 1")
        );

        if (ObjectUtils.isEmpty(flowRecord)) {
            log.info("自动执行到下个节点，但当前节点不存在，不需要处理");
            return null;
        }
        BaseFlowDto baseFlowDto = new BaseFlowDto();
        baseFlowDto.setInfoId(infoId);
        baseFlowDto.setCode(flowRecord.getFlowCode());
        baseFlowDto.setData(data);
        commit(baseFlowDto);
        return baseFlowDto;
    }

    @Override
    public void pauseFlow(String infoId, String msg) {
        WmsFlowRecord record = wmsFlowRecordService.getOne(new LambdaQueryWrapper<WmsFlowRecord>()
                .eq(WmsFlowRecord::getInfoId, infoId)
                .eq(WmsFlowRecord::getStatus, FlowRecordStatusEnum.EXECUTING.getCode())
                .orderByAsc(WmsFlowRecord::getSort)
                .last("limit 1")
        );
        if (ObjectUtils.isEmpty(record)) {
            throw new JeecgBootException("当前流程无法暂停，未找到进行中的节点");
        }
        record.setStatus(FlowRecordStatusEnum.PAUSE.getCode());
        record.setRemark(msg);
        wmsFlowRecordService.updateById(record);
    }

}
